home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / Libraries / SAT 2.3b4 / Demo ƒ / HeartQuest demo ƒ / gameWindow.p < prev    next >
Text File  |  1995-01-22  |  22KB  |  724 lines

  1. {================================================}
  2. {=============== Game window handler ================}
  3. {================================================}
  4.  
  5. { Example file for Ingemars Sprite Animation Toolkit. }
  6. { © Ingemar Ragnemalm 1992-1994 }
  7. { See doc files for legal terms for using this code. }
  8.  
  9. { This file holds the game window and game menu handlers for HeartQuest.}
  10. { This is where most game-specific code goes, except for the code describing}
  11. { each object. }
  12.  
  13. { GameWindInit is called to initialize, which initializes the window and installs}
  14. {handler procedures (note that menus are installed in main.p). It calls the routines}
  15. {to initialize offscreen GrafPorts and all the animated objects. }
  16.  
  17. { When the user selects New Game, StartGame is called to set up a new}
  18. { game, and then MoveIt, the game driver routine is called. }
  19.  
  20. unit GameWindow;
  21.  
  22. interface
  23.  
  24.     uses
  25. {$IFC UNDEFINED THINK_PASCAL}
  26.         Types, Quickdraw, 
  27. {$ENDC}
  28.         TransSkel, SAT, {}
  29.         GameGlobals, sPlayer, sFlypaper, sHeart, sBonus, sPoints, scores, SoundConst, Sound, ClutFade;
  30.  
  31.     procedure DoGameMenu (item: integer);
  32.     procedure GameWindInit;
  33.     procedure DoGameOver;
  34.  
  35.  
  36. implementation
  37.  
  38. {var}
  39. {mp: MonsterPtr; { Bra att ha en global tillgänglig. Dvs praktiskt... }
  40. {    SlemtorksHandlerPtr: ProcPtr;}
  41.  
  42.     procedure InitSprites;
  43.     begin
  44. { Call the init routines for each the sprite unit! Don't forget this! }
  45.         InitFlypaper;
  46.         InitHeart;
  47.         InitPlayer;
  48.         InitBonus;
  49.         InitPoints;
  50.     end;
  51.  
  52.     procedure DrawBackground;
  53.     forward;
  54.  
  55.  
  56. { Setup a bonus level. This is called when a level finishes and all bonus objects were collected.}
  57.     procedure SetupBonusLevel (level: integer);
  58.         var
  59.             p: point;
  60.             i: integer;
  61.             mp: SpritePtr;
  62.             r: rect;
  63.             s: Str255;
  64.             er: EventRecord; {For EventAvail}
  65.             strwidth: integer;
  66.  
  67.     begin { SetupBonusLevel }
  68.  
  69.         SATSoundPlay(drringH, 10, false);
  70. {SATSoundEvents; Not needed since we call SATRun soon.}
  71.  
  72. { Clear the sprite list }
  73.         while gSAT.sRoot <> nil do
  74.             SATKillSprite(gSAT.sRoot);
  75.  
  76.         bonusLevelRunning := true;
  77.  
  78. { Create all the sprites for the level, depending on the level number. }
  79.  
  80. {batchCount := level * 2 + 10;}
  81.         for i := 1 to level * 2 + 10 do
  82.             mp := SATNewSprite(-2, SATRand(gSAT.offSizeH - 112) + 17, -SATRand(400 + 25 * level), @SetupBonusHeart);
  83.  
  84. { Reposition mouse to the center of the game area. }
  85.         p.h := 256;
  86.         p.v := 171;
  87.         SATSetMouse(p);
  88. { Make the player sprite. }
  89.         mp := SATNewSprite(2, (gSAT.offSizeH - xsize) div 2, gSAT.offSizeV div 2, @SetupPlayer);
  90. { Copy gSAT.backScreen to gSAT.offScreen to erase old sprites. }
  91.         CopyBits(gSAT.backScreen.port^.portBits, gSAT.offScreen.port^.portBits, gSAT.offScreen.port^.portRect, gSAT.offScreen.port^.portRect, srcCopy, nil);
  92.         SATRedraw; {replaces the following out-commented lines:}
  93.  
  94.         AddScore(0);
  95. { Do one frame of animation just to draw all the objects. }
  96.         SATRun(false); {false or features^^.PlotFast; slow is ok - no hurry!}
  97.  
  98.         strwidth := StringWidth(MyGetIndString(startbonusStrID));
  99.  
  100. { Draw a message and wait for click- this is a bit ugly. Consider other ways. }
  101.         SetPort(gSAT.wind.port);
  102.         SetRect(r, gSAT.offSizeH div 2 - strwidth div 2 - 5 + 2, gSAT.offSizeV div 2 + 35 + 2, gSAT.offSizeH div 2 + strwidth div 2 + 5 + 2, gSAT.offSizeV div 2 + 60 + 2); {offset by 2 pixels}
  103.         PaintRect(r);
  104.         SetRect(r, gSAT.offSizeH div 2 - strwidth div 2 - 5, gSAT.offSizeV div 2 + 35, gSAT.offSizeH div 2 + strwidth div 2 + 5, gSAT.offSizeV div 2 + 60);
  105.         EraseRect(r);
  106.  
  107.         MoveTo(gSAT.offSizeH div 2 - strwidth div 2, gSAT.offSizeV div 2 + 50);
  108.         DrawString(MyGetIndString(startbonusStrID)); {str 16: Click mouse for bonus level!}
  109.  
  110. {Wait until something happens}
  111.         FlushEvents(everyEvent, 0); { To forget events, like mouse clicks etc. }
  112.         repeat
  113.         until EventAvail(mDownMask + keyDownMask, er);
  114.  
  115. { Redraw to get rid of the message we just made. }
  116.         SATRedraw;
  117.     end; { SetupBonusLevel }
  118.  
  119. { Setup a new level. This is called when the game starts ans at each new level.}
  120.     procedure SetupLevel (level: integer);
  121.         var
  122.             p: point;
  123.             i: integer;
  124.             mp, oldmp: SpritePtr;
  125.             r: rect;
  126.             s: Str255;
  127.             er: EventRecord; {For EventAvail}
  128.             strwidth: integer;
  129.  
  130. { A routine to create a bunch of hearts }
  131.         procedure MakeHearts (howmany: integer);
  132.             var
  133.                 i: integer;
  134.                 mp: SpritePtr;
  135.         begin
  136.             for i := 1 to howmany do
  137.                 case SATRand(4) of
  138.                     0: 
  139.                         mp := SATNewSprite(-2, SATRand(gSAT.offSizeH - 112) + 17, 0, @SetupHeart);
  140.                     1: 
  141.                         mp := SATNewSprite(-2, SATRand(gSAT.offSizeH - 112) + 17, gSAT.offSizeV - 32, @SetupHeart);
  142.                     2: 
  143.                         mp := SATNewSprite(-2, 0, SATRand(gSAT.offSizeV - 32) + 17, @SetupHeart);
  144.                     3: 
  145.                         mp := SATNewSprite(-2, gSAT.offSizeH - xsize, SATRand(gSAT.offSizeV - 32) + 17, @SetupHeart);
  146.                 end;
  147.         end;
  148.  
  149.     begin { SetupLevel }
  150.  
  151. { Clear the sprite list }
  152.         while gSAT.sRoot <> nil do
  153.             SATKillSprite(gSAT.sRoot);
  154.  
  155. { Create all the sprites for the level, depending on the level number. }
  156.         case level of
  157.             1: 
  158.                 begin
  159.                     bonus := 250;
  160.                     MakeHearts(6);
  161.                     mp := SATNewSprite(-3, 10, 10, @SetupFlypaper);
  162.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, gSAT.offSizeV - 32, @SetupFlypaper);
  163.                 end;
  164.             2: 
  165.                 begin
  166.                     bonus := 300;
  167.                     MakeHearts(10);
  168.                     mp := SATNewSprite(-3, 10, 10, @SetupFlypaper);
  169.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, 20, @SetupFlypaper);
  170.                     mp := SATNewSprite(-3, 20, gSAT.offSizeV - 32, @SetupFlypaper);
  171.                 end;
  172.             3: 
  173.                 begin
  174.                     MakeHearts(12);
  175.                     bonus := 350;
  176.                     mp := SATNewSprite(-3, 5, 5, @SetupFlypaper);
  177.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, 5, @SetupFlypaper);
  178.                     mp := SATNewSprite(-3, 5, gSAT.offSizeV - 32, @SetupFlypaper);
  179.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, gSAT.offSizeV - 32, @SetupFlypaper);
  180.                 end;
  181.             4: 
  182.                 begin
  183.                     MakeHearts(12);
  184.                     bonus := 350;
  185.                     mp := SATNewSprite(-3, 5, 5, @SetupFlypaper);
  186.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, 5, @SetupFlypaper);
  187.                     mp := SATNewSprite(-3, 5, gSAT.offSizeV - 32, @SetupFlypaper);
  188.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, gSAT.offSizeV - 32, @SetupFlypaper);
  189.                     mp := SATNewSprite(-3, 5, (gSAT.offSizeV - 32) mod 2, @SetupFlypaper);
  190.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, (gSAT.offSizeV - 32) mod 2, @SetupFlypaper);
  191.                 end;
  192.             5: 
  193.                 begin
  194.                     MakeHearts(10);
  195.                     bonus := 380;
  196.                     mp := SATNewSprite(-3, 5, 5, @SetupFlypaper);
  197.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, 5, @SetupFlypaper);
  198.                     mp := SATNewSprite(-3, 5, gSAT.offSizeV - 32, @SetupFlypaper);
  199.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, gSAT.offSizeV - 32, @SetupFlypaper);
  200.                 end;
  201.             6: 
  202.                 begin
  203.                     MakeHearts(12);
  204.                     bonus := 420;
  205.                     mp := SATNewSprite(-3, 5, 5, @SetupFlypaper);
  206.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, 5, @SetupFlypaper);
  207.                     mp := SATNewSprite(-3, 5, gSAT.offSizeV - 32, @SetupFlypaper);
  208.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, gSAT.offSizeV - 32, @SetupFlypaper);
  209.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, (gSAT.offSizeV - 32) mod 2, @SetupFlypaper);
  210.                 end;
  211.             otherwise
  212.                 begin
  213.                     MakeHearts(level * 2);
  214.                     bonus := 300 + 20 * level;
  215.                     for i := 0 to level - 1 do
  216.                         begin
  217.                             case SATRand(6) of
  218.                                 0: 
  219.                                     mp := SATNewSprite(-3, 5, 5, @SetupFlypaper);
  220.                                 1: 
  221.                                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, 5, @SetupFlypaper);
  222.                                 2: 
  223.                                     mp := SATNewSprite(-3, 5, 300, @SetupFlypaper);
  224.                                 3: 
  225.                                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, gSAT.offSizeV - 32, @SetupFlypaper);
  226.                                 4: 
  227.                                     mp := SATNewSprite(-3, (gSAT.offSizeH - xsize - 32) div 2, 5, @SetupFlypaper);
  228.                                 5: 
  229.                                     mp := SATNewSprite(-3, (gSAT.offSizeH - xsize - 32), gSAT.offSizeV - 32, @SetupFlypaper);
  230.                             end; { case }
  231.                         end;
  232.                 end;
  233.         end;
  234.  
  235.         bonusLevelRunning := false;
  236.  
  237. { Reposition mouse to the center of the game area. }
  238.         p.h := 256;
  239.         p.v := 171;
  240.         SATSetMouse(p);
  241. { Make the player sprite. }
  242.         mp := SATNewSprite(2, (gSAT.offSizeH - xsize) div 2, gSAT.offSizeV div 2, @SetupPlayer);
  243.  
  244. {Fade out while we redraw!}
  245.         FadeScreen(20, true, fadeTo);
  246.  
  247. { Copy gSAT.backScreen to gSAT.offScreen to erase old sprites. }
  248.         CopyBits(gSAT.backScreen.port^.portBits, gSAT.offScreen.port^.portBits, gSAT.offScreen.port^.portRect, gSAT.offScreen.port^.portRect, srcCopy, nil);
  249.         SATRedraw;
  250.  
  251.         AddScore(0);
  252. { Do one frame of animation just to draw all the objects. }
  253.         SATRun(false); {false or features^^.PlotFast; slow is ok - no hurry!}
  254.  
  255.         if level = 1 then
  256.             s := MyGetIndString(startgameStrID)  {str 16: Click the mouse to start the game.}
  257.         else
  258.             s := stringof(MyGetIndString(startlevelStrID), level : 1, '.'); {str 17: Click the mouse to start level }
  259.  
  260.         if level = 1 then
  261.             strwidth := StringWidth(s)
  262.         else
  263.             strwidth := StringWidth(s);
  264.  
  265. { Draw a message and wait for click- this is a bit ugly. Consider other ways. }
  266.         SetPort(gSAT.wind.port);
  267.         SetRect(r, gSAT.offSizeH div 2 - strwidth div 2 - 5 + 2, gSAT.offSizeV div 2 + 35 + 2, gSAT.offSizeH div 2 + strwidth div 2 + 5 + 2, gSAT.offSizeV div 2 + 60 + 2); {offset by 2 pixels}
  268.         PaintRect(r);
  269.         SetRect(r, gSAT.offSizeH div 2 - strwidth div 2 - 5, gSAT.offSizeV div 2 + 35, gSAT.offSizeH div 2 + strwidth div 2 + 5, gSAT.offSizeV div 2 + 60);
  270.         EraseRect(r);
  271.  
  272.         MoveTo(gSAT.offSizeH div 2 - strwidth div 2, gSAT.offSizeV div 2 + 50);
  273.         DrawString(s);
  274.  
  275.         FadeScreen(20, false, fadeTo);
  276.  
  277. {Wait until something happens}
  278.         FlushEvents(EveryEvent, 0); { To forget events, like mouse clicks etc. }
  279.         repeat
  280.         until EventAvail(mDownMask + keyDownMask, er);
  281.  
  282. { Redraw to get rid of the message we just made. }
  283.         SATRedraw;
  284.     end; { SetupLevel }
  285.  
  286. { Start a new game. Initialize level, score, number of lives, and call setuplevel to make the first level. }
  287.     procedure StartGame;
  288.     begin
  289.         ZeroScore;
  290.         level := 1;
  291.  
  292.         bonusesCollected := 0;
  293.  
  294.         SetupLevel(level);
  295.     end;
  296.  
  297. { Game Over procedure. Draw "Game Over" text, check high scores. }
  298.  
  299.     procedure DoGameOver;
  300.         var
  301. { Variables for the Game Over-box }
  302.             theRect, theRect2: rect;
  303.             thePict: Handle;
  304.             bredd, i: integer;
  305.             dx, dy: integer;
  306.             time: longint;
  307.     begin
  308.         SetItem(GameMenu, Pause, MyGetIndString(pauseStrID)); {str 18: Pause}
  309. { Game Over display! }
  310.         SetPort(gSAT.wind.port);
  311.         if gSAT.colorFlag and (gSAT.initDepth <> 1) then
  312.             thePICT := GetResource('PICT', 129)
  313.         else
  314.             thePICT := GetResource('PICT', 128);
  315.         theRect := PicHandle(thePICT)^^.picFrame;
  316.         theRect.right := theRect.right - theRect.left;
  317.         theRect.bottom := theRect.bottom - theRect.top;
  318.         theRect.top := 0;
  319.         theRect.left := 0;
  320.  
  321.         dx := (gSAT.offSizeH - (theRect.right - theRect.left)) div 2 - theRect.left;
  322.         dy := (gSAT.offSizeV - (theRect.bottom - theRect.top)) div 2 - theRect.top;
  323.         OffsetRect(theRect, dx, dy);
  324.  
  325.         bredd := theRect.right - theRect.left;
  326.         theRect2 := theRect;
  327.  
  328.         i := 1;
  329.         repeat
  330.             time := TickCount;
  331.             theRect.right := theRect2.right - bredd * (80 - i) div 160;
  332.             theRect.left := theRect2.left + bredd * (80 - i) div 160;
  333.             DrawPicture(PicHandle(thePICT), TheRect);
  334.             i := i + TickCount - time;
  335.         until i >= 80;
  336.  
  337.         SetPort(gSAT.offScreen.port);
  338.         DrawPicture(PicHandle(thePICT), TheRect);
  339.         SetPort(gSAT.wind.port);
  340.  
  341.         InvalRect(theRect);
  342.  
  343.         SATSoundShutUp; { Dispose of sound channel }
  344.  
  345.         FlushEvents(everyEvent, 0); { To forget events, like mouse clicks etc. }
  346.         ShowCursor;
  347.  
  348.         UpdateHigh; { Game over, was it high score? }
  349.     end;
  350.  
  351.  
  352. { This routine is the game driver. It calls the "Animator" package until the game ends or is paused. }
  353. { I also read the keyboard here. This could optionally be moved to the "player object" module. }
  354.  
  355.     procedure MoveIt;
  356.         var
  357.             fr, tr, r: Rect;
  358.             pt: Point;
  359.             t, l: longint;
  360.             theEvent: EventRecord; { för att testa musklick }
  361. { To check for key clicks with GetKeys:  - no longer used. km: KeyMap;}
  362.             hasEvent: Boolean;
  363.             ignore: OSerr;
  364.     begin
  365.         stillrunning := true; { A flag that tells whether or not to quit this routine. }
  366.  
  367.         HideCursor; { NOTE: No matter how we leave the MoveIt procedure, we should ShowCursor. }
  368.  
  369.         pt.h := 256;
  370.         pt.v := 171;
  371.         SATSetMouse(pt);
  372.  
  373. { Main loop! Keep running until the game is paused or ends. }
  374.         while stillrunning = true do
  375.             begin
  376.                 t := TickCount;
  377.                 SetPort(gSAT.offScreen.port);
  378.  
  379. {Reset booleans that will be set by the sprites.}
  380.                 bonusObjectRunning := false;
  381.                 levelCompleted := true;
  382.  
  383. { Here is the real heart of the loop: call Animator once per loop. It will call all the objects. }
  384.                 SATRun(features^^.plotFast);
  385. {SATSoundEvents; No longer needed - included in SATRun!}
  386.  
  387. { All the rest of the main loop is game specific, next level, bonus handling, etc. }
  388.  
  389. {Decrease bonus. Out of bonus? Does not apply to bonus levels.}
  390.                 if not bonusLevelRunning then
  391.                     if not bonusObjectRunning or features^^.macho then
  392.                         if bonus > 0 then
  393.                             begin
  394.                                 bonus := bonus - 1;
  395.                                 if bonus mod 10 = 0 then
  396.                                     begin
  397.                                         AddScore(0);
  398.                                         if features^^.macho then
  399.                                             if bonus < 110 then
  400.                                                 SATSoundPlay(TickSndH, 0, false);
  401.                                     end
  402.                                 else if features^^.macho then
  403.                                     if bonus < 26 then
  404.                                         if bonus mod 5 = 0 then
  405.                                             SATSoundPlay(TickSndH, 0, false);
  406.                             end
  407.                         else if features^^.macho then
  408.                             stillrunning := false;
  409.  
  410.                 if levelCompleted then{(batchcount < 1)}
  411.         {All hearts collected?}
  412.                     begin
  413.                         SATSoundShutUp;
  414.  
  415.                         SATSoundPlay(sadarSndH, 0, true);
  416.                         repeat
  417.                             SATSoundEvents
  418.                         until SATSoundDone;
  419.  
  420. {If it isn't a bonus level, we should give the player the bonus remaining}
  421.                         if not bonusLevelRunning then
  422.                             if bonus > 0 then
  423.                                 while bonus > 0 do
  424.                                     begin
  425.                                         bonus := bonus - 10;
  426.  
  427.                                         SATSoundPlay(KlounkSndH, 0, true);
  428.                                         repeat
  429.                                             SATSoundEvents
  430.                                         until SATSoundDone;
  431.  
  432.                                         if bonus < 0 then
  433.                                             begin
  434.                                                 l := bonus;
  435.                                                 bonus := 0;
  436.                                                 AddScoreS(10 + l); {A special synchronous version of AddScore}
  437.                                             end
  438.                                         else
  439.                                             AddScoreS(10); { Bonus! }
  440.                                     end { if bonus > 0 }
  441.                             else if features^^.macho then
  442.                                 stillrunning := false; { If no bonus, game over }
  443.  
  444. {Level finished? Do we want a new level?}
  445.                         if (stillrunning and features^^.macho) or (level < 3) then
  446.                             if bonusesCollected >= kBonusLevelTresh then
  447.                                 begin
  448.                                     SetupBonusLevel(level);
  449.                                     AddScoreS(0); {To update the level number}
  450.                                     bonusesCollected := bonusesCollected - kBonusLevelTresh;
  451.                                 end
  452.                             else
  453.                                 begin
  454.                                     level := level + 1;
  455.                                     SetupLevel(level);
  456.                                     AddScoreS(0); {To update the level number}
  457.                                 end
  458.                         else
  459.                             stillrunning := false;
  460.                     end; {if (batchcount < 1)}
  461.  
  462. { Check for keys being pressed }
  463.                 if features^^.allowBG then { if we are allowed to use the normal method }
  464.                     begin
  465.                         SystemTask;
  466. { Replaced the following call by WaitNextEvent if you want to be modern (but less backwards compatible). :-) }
  467.                         hasEvent := GetNextEvent(keyDownMask, theEvent)
  468.                     end
  469.                 else {Otherwise, use the faster GetOSEvent}
  470.                     begin
  471.                         hasEvent := GetOSEvent(keyDownMask, theEvent)
  472.                     end;
  473.  
  474. {If there was a keydown, see if it was one of the menu options that we support when running.}
  475.                 if hasEvent then { there was a keydown }
  476.                     if BitAnd(theEvent.modifiers, cmdKey) <> 0 then
  477.                         begin
  478.                             case char(BitAnd(theEvent.message, charCodeMask)) of
  479.                                 'p': 
  480.                                     begin
  481.                                         PauseFlag := true;
  482.                                         SATSoundShutUp; { Dispose of sound channel }
  483.                                         ShowCursor;
  484.                                         flushevents(6 + 8, 0); { In order to forget the cmd-p }
  485.                                         SetItem(GameMenu, Pause, MyGetIndString(resumeStrID)); {str 19: Resume}
  486.                                         exit(MoveIt);
  487.                                     end;
  488.                                 '.': 
  489.                                     StillRunning := false;
  490.                                 'q': 
  491.                                     begin
  492.                                         StillRunning := false;
  493.                                         SkelWhoa;
  494.                                     end;
  495.                                 's': 
  496.                                     begin
  497.                                         DoGameMenu(sound);
  498.                                     end;
  499.                                 otherwise
  500.                                     ;
  501.                             end; {case}
  502.                         end
  503.                     else if BitAnd(theEvent.message, charCodeMask) = 27 then {ESC}
  504.                         StillRunning := false;
  505.  
  506. { Delay, using TickCount so it doesn't matter how fast our Mac is. }
  507.                 while ((TickCount - t) < 3) do
  508.                     ;
  509.  
  510.             end; { while stillrunning (main loop) }
  511.  
  512.         DoGameOver;
  513.  
  514.         FlushEvents(mouseDown + keyDown, 0); { In order to forget the cmd-p }
  515.     end;
  516.  
  517.  
  518. {We used to draw the background ourselves rather than using a simple backdrop PICT, to save space and to get}
  519. {the dithered background. However, using the shades in the object drawing part of ClarisWorks, I can make PICT}
  520. {resources that are fairly small, so I use that instead now.}
  521. {Thus, DrawBackground ONLY draws the trees!}
  522.     procedure DrawBackground;
  523.         var
  524.             ph: PicHandle;
  525.             ignore: OSErr;
  526.             col: RGBColor;
  527.             thinr, r: Rect;
  528.             i, j: integer;
  529.  
  530.             posH, posV, scale, height, width: longint; {For scaling the trees}
  531.     begin
  532.         SATSetPortBackScreen;
  533.         SetRect(r, 0, 0, gSAT.offSizeH, gSAT.offSizeV);
  534.  
  535. {Draw trees using PICTs!}
  536.  
  537. {First get the right PICT}
  538.         if gSAT.initDepth = 1 then
  539.             begin
  540.                 ph := GetPicture(135); {bw tree PICT}
  541.             end
  542.         else
  543.             begin
  544.                 ph := GetPicture(134); {color tree PICT}
  545.             end;
  546.         if ph = nil then
  547.             exit(DrawBackground);
  548.  
  549. {Scale by ph^^.picframe}
  550.         for i := 0 to 10 do
  551. {For more trees: for j := i to 4 do}
  552.             begin
  553.                 posH := SATRand(gSAT.offSizeH);
  554.                 posV := gSAT.offSizeV div 2 + longint(i) * i * gSAT.offSizeV div 300;
  555.  
  556.                 scale := (posV - gSAT.offSizeV div 4) div 17;
  557.                 height := scale * (ph^^.picframe.bottom - ph^^.picframe.top) div 40;
  558.                 width := scale * (ph^^.picframe.right - ph^^.picframe.left) div 40;
  559.  
  560.                 r.top := posV - height;
  561.                 r.bottom := posV;
  562.                 r.right := posH + width;
  563.                 r.left := posH;
  564.  
  565.                 DrawPicture(ph, r);
  566.             end;
  567.  
  568.         ReleaseResource(handle(ph));
  569.  
  570.         CopyBits(gSAT.backScreen.port^.portBits, gSAT.offScreen.port^.portBits, gSAT.backScreen.port^.portRect, gSAT.backScreen.port^.PortRect, srcCopy, nil);
  571.         SATSetPortScreen;
  572.         SATRedraw;
  573. {CopyBits(gSAT.backScreen^.portBits, gSAT.wind^.portBits, gSAT.backScreen^.portRect, gSAT.backScreen^.PortRect, srcCopy + ditherCopy, nil);}
  574.     end;
  575.  
  576.  
  577.     procedure GameWindUpdate;
  578.         var
  579.             s: str255;
  580.             r: Rect;
  581.             crsr: CursHandle;
  582.     begin
  583. {When the depth has changed, the game wind will get an update event,}
  584. {so let's give SAT a chance to update itself before updating!}
  585.  
  586.         crsr := GetCursor(WatchCursor);
  587.         SetCursor(crsr^^);
  588.         if SATDepthChangeTest then
  589.             begin
  590.                 DrawBackground;    {Redraw trees}
  591.             end;
  592.         ReleaseResource(handle(crsr));
  593.         InitCursor;
  594.  
  595.         SATRedraw;
  596.         AddScore(0);
  597.     end;
  598.  
  599.     procedure DoGameMenu (item: integer);
  600.     begin
  601.         case (item) of
  602.             run: 
  603.                 begin
  604. { Test if we have Color QD, and if so, test bit depth! Alert if features^^.PlotFast.}
  605.                     if SATDepthChangeTest then {Update if necessary}
  606.                         DrawBackground;
  607.                     if not ((gSAT.initDepth = 1) or (gSAT.initDepth = 4) or (gSAT.initDepth = 8)) and features^^.PlotFast then
  608.                         begin
  609.                             SATReportStr(MyGetIndString(pleaseuncheckStrID));
  610. {str 23: Please uncheck ''Fast animation'' or set the monitor to 1-, 4- or 8-bit mode in the Control Panel.}
  611.                             exit(DoGameMenu);
  612.                         end;
  613.                     if pauseFlag then
  614.                         if SATQuestionStr(MyGetIndString(endStrID)) then {str 24: End the Current game?}
  615.                             DoGameMenu(abort)
  616.                         else
  617.                             exit(DoGameMenu);
  618.                     DisableItem(gameMenu, macho);
  619.                     ShowWindow(gSAT.wind.port);
  620.                     SelectWindow(gSAT.wind.port);
  621.                     StartGame;
  622.                     GameWindUpdate;
  623.                     MoveIt;
  624.                     if not pauseFlag then
  625.                         EnableItem(GameMenu, macho);
  626.                 end;
  627.             sound: 
  628.                 begin
  629.                     features^^.sound := not features^^.sound;
  630.                     CheckItem(GameMenu, sound, features^^.sound);
  631.                     if features^^.sound then { Tell the sound package our settings, so we don't have to bother. }
  632.                         SATSoundOn
  633.                     else
  634.                         SATSoundOff;
  635.                     ChangedResource(handle(features));
  636.                 end;
  637.             macho: 
  638.                 begin
  639.                     features^^.macho := not features^^.macho;
  640.                     CheckItem(GameMenu, macho, features^^.macho);
  641.                     ChangedResource(handle(features));
  642.                 end;
  643.             AllowBG: 
  644.                 begin
  645.                     features^^.AllowBG := not features^^.AllowBG;
  646.                     CheckItem(GameMenu, AllowBG, features^^.AllowBG);
  647.                     ChangedResource(handle(features));
  648.                 end;
  649.             FastAnimation: 
  650.                 begin
  651.                     features^^.PlotFast := not features^^.PlotFast;
  652.                     CheckItem(GameMenu, FastAnimation, features^^.PlotFast);
  653.                     ChangedResource(handle(features));
  654.                 end;
  655.             pause: 
  656.                 begin
  657. { Pause is only interesting here as "resume". }
  658.                     if pauseFlag then
  659.                         begin
  660. { Test if we have Color QD, and if so, test bit depth! Alert if features^^.PlotFast.}
  661.                             if SATDepthChangeTest then {Update if necessary}
  662.                                 DrawBackground;
  663.                             if not ((gSAT.initDepth = 1) or (gSAT.initDepth = 4) or (gSAT.initDepth = 8)) and features^^.PlotFast then
  664.                                 begin
  665.                                     SATReportStr(MyGetIndString(pleaseuncheckStrID)); {str 23}
  666.                                     exit(DoGameMenu);
  667.                                 end;
  668.                             SetItem(GameMenu, pause, MyGetIndString(pauseStrID)); {str 18}
  669.                             pauseFlag := false;
  670.                             ShowWindow(gSAT.wind.port);
  671.                             SelectWindow(gSAT.wind.port);
  672.                             GameWindUpdate;
  673.                             MoveIt;
  674.                             if not pauseFlag then
  675.                                 EnableItem(GameMenu, macho);
  676.                         end;
  677.                 end;
  678.             abort: 
  679.                 begin
  680.                     if pauseFlag then
  681.                         begin
  682.                             SetItem(GameMenu, Pause, MyGetIndString(pauseStrID)); {str 18}
  683.                             DoGameOver;
  684.                             pauseFlag := false;
  685.                             EnableItem(GameMenu, macho);
  686.                         end
  687.                 end;
  688.         end;
  689.     end;
  690.  
  691.     procedure GameWindMouse (thePoint: Point; theTime: longint; theMods: integer; myProc: ProcPtr);
  692.     begin
  693.         if pauseFlag then
  694.             DoGameMenu(pause)
  695.         else
  696.             DoGameMenu(run);
  697.     end;
  698.  
  699.     procedure GameWindIdle;
  700.     begin
  701.     end;
  702.  
  703.     procedure GameWindClose;
  704.     begin
  705.     end;
  706.  
  707.     procedure GameWindInit;
  708.     begin
  709. { Tell TransSkel to handle all the tedious things with gSAT.wind. }
  710.         dummy := SkelWindow(gSAT.wind.port, @GameWindMouse, nil, @GameWindUpdate, nil, @GameWindClose, nil, @GameWindIdle, false);
  711.  
  712. { Initialize the sprites }
  713.         InitSprites;
  714.  
  715. {We draw some of the background -the trees - ourselves in this game.}
  716.         DrawBackground;
  717.  
  718. { Draw the contents of the window (to give the user something to look at during the rest of startup). }
  719.         ShowWindow(gSAT.wind.port);
  720.         SelectWindow(gSAT.wind.port);
  721.         SATRedraw;
  722.     end;
  723.  
  724. end.